﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.Json.Serialization;
using System.Threading.Tasks;

namespace LightCAD.Core
{
    public class Arc2d : ICurve2d
    {
        public Curve2dType Type => Curve2dType.Arc2d;

        [JsonInclude]
        public Vector2d Center;
        public double Radius { get; set; }
        public double StartAngle { get; set; }
        public double EndAngle { get; set; }

        [JsonIgnore]
        public bool IsClosed => false;
        [JsonIgnore]
        public object Source { get; set; }
        public string Name { get; set; }

        public void Copy(ICurve2d src)
        {
            var arc = src as Arc2d;
            this.Center = arc.Center;
            this.Radius = arc.Radius;
            this.StartAngle = arc.StartAngle;   
            this.EndAngle = arc.EndAngle;
            this.Name = arc.Name;
        }
        public ICurve2d Clone()
        {
            var newObj = new Arc2d();
            newObj.Copy(this);
            return newObj;
        }
        object ICloneable.Clone()
        {
            return this.Clone();
        }


        /// <summary>
        /// 获取坐标
        /// </summary>
        /// <param name="pt">圆心</param>
        /// <param name="ang">角度</param>
        /// <param name="dst">半径</param>
        /// <returns></returns>
        public static Vector2d GetPointByArc(Vector2d pt, double ang, double dst)
        {
            ang = FixAngle(ang);
            return new Vector2d((Cos(ang) * dst) + pt.X, (Sin(ang) * dst) + pt.Y);
        }
        public static bool AreEqual(double val1, double val2, double eq)
        {
            return (Math.Abs((double)(val1 - val2)) < eq);
        }
        public static double Sin(double angleRadius)
        {
            double eq = 1E-07;
            if (AreEqual(angleRadius, 0.0, eq))
            {
                return 0.0;
            }
            if (AreEqual(angleRadius, 1.5707963267948, eq))
            {
                return 1.0;
            }
            if (AreEqual(angleRadius, 3.1415926535898, eq))
            {
                return 0.0;
            }
            if (AreEqual(angleRadius, 4.7123889803844, eq))
            {
                return -1.0;
            }
            if (AreEqual(angleRadius, 6.2831853071796, eq))
            {
                return 0.0;
            }
            return Math.Sin(angleRadius);
        }
        public static double Cos(double angleRadius)
        {
            double eq = 1E-07;
            if (AreEqual(angleRadius, 0.0, eq))
            {
                return 1.0;
            }
            if (AreEqual(angleRadius, 1.5707963267948, eq))
            {
                return 0.0;
            }
            if (AreEqual(angleRadius, 3.1415926535898, eq))
            {
                return -1.0;
            }
            if (AreEqual(angleRadius, 4.7123889803844, eq))
            {
                return 0.0;
            }
            if (AreEqual(angleRadius, 6.2831853071796, eq))
            {
                return 1.0;
            }
            return Math.Cos(angleRadius);
        }
        public static double FixAngle(double inangle)
        {
            double eq = 1E-06;
            if (AreEqual(inangle, 6.2831853071796, eq))
            {
                return 6.2831853071796;
            }
            double num2 = inangle;
            num2 = num2 % 6.2831853071796;
            if (num2 > (6.2831853071796 + eq))
            {
                num2 -= 6.2831853071796;
            }
            if ((num2 + eq) < 0.0)
            {
                num2 += 6.2831853071796;
            }
            if (AreEqual(num2, 0.0, eq))
            {
                return 0.0;
            }
            if (AreEqual(num2, 1.5707963267948, eq))
            {
                return 1.5707963267948;
            }
            if (AreEqual(num2, 3.1415926535898, eq))
            {
                return 3.1415926535898;
            }
            if (AreEqual(num2, 4.7123889803844, eq))
            {
                return 4.7123889803844;
            }
            if (AreEqual(num2, 6.2831853071796, eq))
            {
                return 6.2831853071796;
            }
            return num2;
        }
        public static double Distance2D(Vector2d P, Vector2d pt)
        {
            return Math.Sqrt(((P.X - pt.X) * (P.X - pt.X)) + ((P.Y - pt.Y) * (P.Y - pt.Y)));
        }
        public static double GetAngle(Vector2d p1, Vector2d p2)
        {
            if (AreEqual(Distance2D(p1,p2), 0.0, 1E-08))
            {
                return 0.0;
            }
            return FixAngle(Math.Atan2(p2.Y - p1.Y, p2.X - p1.X));
        }
        public static void getmidp()
        {
            //            import math

            //# 圆弧的起始和结束坐标
            //startX = 1
            //startY = 2
            //endX = 4
            //endY = 6

            //# 圆弧半径
            //radius = 5

            //# 圆心坐标
            //centerX = (startX + endX) / 2
            //centerY = (startY + endY) / 2

            //# 计算起始角度和结束角度（以x轴正方向为0度）
            //angle_start = math.atan2(startY - centerY, startX - centerX)
            //angle_end = math.atan2(endY - centerY, endX - centerX)

            //# 计算中间角度（取两个角度的平均值）
            //angle_mid = (angle_start + angle_end) / 2

            //# 计算中间点坐标
            //midX = centerX + radius * math.cos(angle_mid)
            //midY = centerY + radius * math.sin(angle_mid)

            //print("The midpoint of the arc:")
            //print("X:", midX)
            //print("Y:", midY)

        }
         
        public static Box2d GetArcBox(Vector2d center, double radius, double startAngle, double endAngle)
        {
            Box2d box = new Box2d();
            //if (IsCircle(StartAngle, EndAngle))
            //{
            //    box.AddPoint(Center);
            //    box.AddWidth(Radius);
            //    return box;
            //}
            Vector2d pt = GetPointByArc(center, startAngle, radius);
            Vector2d point2 = GetPointByArc(center, endAngle, radius);
            Vector2d point3 = new Vector2d(pt.X, pt.Y);
            Vector2d point4 = new Vector2d(point2.X, point2.Y);
            Vector2d point5 = new Vector2d(pt.X, pt.Y);
            Vector2d point6 = new Vector2d(pt.X, pt.Y);
            Vector2d point7 = new Vector2d(pt.X, pt.Y);
            Vector2d point8 = new Vector2d(pt.X, pt.Y);
            double[] numArray = new double[] { 0.0, 1.5707963267948, 3.1415926535898, 4.7123889803844 };
            Vector2d point9 = GetPointByArc(center, numArray[0], radius);
            Vector2d point10 = GetPointByArc(center, numArray[1], radius);
            Vector2d point11 = GetPointByArc(center, numArray[2], radius);
            Vector2d point12 = GetPointByArc(center, numArray[3], radius);
            double num = startAngle;
            double num2 = endAngle;
            num2 -= num;
            numArray[0] -= num;
            numArray[1] -= num;
            numArray[2] -= num;
            numArray[3] -= num;
            num = 0.0;
            //if (num2 < 0.0)
            //{
            //    num2 += 6.2831853071796;
            //}
            //if (numArray[0] < 0.0)
            //{
            //    numArray[0] += 6.2831853071796;
            //}
            //if (numArray[1] < 0.0)
            //{
            //    numArray[1] += 6.2831853071796;
            //}
            //if (numArray[2] < 0.0)
            //{
            //    numArray[2] += 6.2831853071796;
            //}
            //if (numArray[3] < 0.0)
            //{
            //    numArray[3] += 6.2831853071796;
            //}
            //if ((numArray[0] > num) && (numArray[0] < num2))
            //{
            //    point5.CopyFrom(point9); 
            //}
            //if ((numArray[1] > num) && (numArray[1] < num2))
            //{
            //    point6.CopyFrom(point10);
            //}
            //if ((numArray[2] > num) && (numArray[2] < num2))
            //{
            //    point7.CopyFrom(point11);
            //}
            //if ((numArray[3] > num) && (numArray[3] < num2))
            //{
            //    point8.CopyFrom(point12);
            //}
            //box.a(point3);
            //box.AddPoint(point4);
            //box.AddPoint(point5);
            //box.AddPoint(point6);
            //box.AddPoint(point7);
            //box.AddPoint(point8);
            return box;
        }
        public static bool ArcFrom3Points(Vector2d sp, Vector2d ep, Vector2d mp, out Vector2d cen, out double rad, out double sa, out double ea)
        {
            Vector2d pt = new Vector2d();
            Vector2d point2 = new Vector2d();
            double ang = GetAngle(sp, mp) + 1.5707963267948;
            double num2 = GetAngle(sp, ep) + 1.5707963267948;
            pt.X = (sp.X / 2.0) + (mp.X / 2.0);
            pt.Y = (sp.Y / 2.0) + (mp.Y / 2.0);
            point2.X = (sp.X / 2.0) + (ep.X / 2.0);
            point2.Y = (sp.Y / 2.0) + (ep.Y / 2.0);
            Vector2d point3 = GetPointByArc(pt, ang, 100.0);
            Vector2d point4 = GetPointByArc(point2, num2, 100.0);
            double num3 = num2 - ang;
            if (num3 < 0.0)
            {
                num3 += 6.2831853071796;
            }
            cen = new Vector2d();
            IntersectionLL2D(pt, point3, point2, point4,out cen);
            rad = Distance2D(cen, sp);
            if (num3 > 3.1415926535898)
            {
                sa = GetAngle(cen, ep);
                ea = GetAngle(cen, sp);
            }
            else
            {
                sa = GetAngle(cen, sp);
                ea = GetAngle(cen, ep);
            }
            return true;
        }
        public static int IntersectionLL2D(Vector2d p1, Vector2d p2, Vector2d p3, Vector2d p4,out Vector2d retpt)
        {
            double x = p1.X;
            double num2 = p2.X;
            double num3 = p3.X;
            double num4 = p4.X;
            double y = p1.Y;
            double num6 = p2.Y;
            double num7 = p3.Y;
            double num8 = p4.Y;
            double num9 = (((x + num2) + num3) + num4) / 4.0;
            double num10 = (((y + num6) + num7) + num8) / 4.0;
            x -= num9;
            num2 -= num9;
            num3 -= num9;
            num4 -= num9;
            y -= num10;
            num6 -= num10;
            num7 -= num10;
            num8 -= num10;
            double num11 = num8 - num7;
            double num12 = num3 - num4;
            double num13 = num6 - y;
            double num14 = x - num2;
            double num15 = (num11 * num14) - (num13 * num12);
            retpt.X = 0;
            retpt.Y = 0;
            if (AreEqual(num15, 0.0, 1E-06))
            {
                return 0;
            }
            double num16 = (num4 * num7) - (num3 * num8);
            double num17 = (num2 * y) - (x * num6);
            double num18 = (num12 * num17) - (num14 * num16);
            double num19 = (num13 * num16) - (num11 * num17);
            retpt.X = (num18 / num15) + num9;
            retpt.Y = (num19 / num15) + num10;
 
            return 1;
        }

        public double GetDegreesByTwoLine(Vector2d line1start, Vector2d line1End, Vector2d line2start, Vector2d line2End)
        {
            double x1 = line1start.X;
            double y1 = line1start.Y;
            double x2 = line1End.X;
            double y2 = line1End.Y;
            double x3 = line2start.X;
            double y3 = line2start.Y;
            double x4 = line2End.X;
            double y4 = line2End.Y;

            // 计算线段的向量表示
            double v1x = x2 - x1;
            double v1y = y2 - y1;
            double v2x = x4 - x3;
            double v2y = y4 - y3;

            // 计算向量的内积
            double dotProduct = v1x * v2x + v1y * v2y;

            // 计算向量的长度
            double magnitudeV1 = Math.Sqrt(v1x * v1x + v1y * v1y);
            double magnitudeV2 = Math.Sqrt(v2x * v2x + v2y * v2y);

            // 计算夹角余弦值
            double cosine = dotProduct / (magnitudeV1 * magnitudeV2);

            // 将夹角余弦值转换为角度
            double angleRadians = Math.Acos(cosine);
            double angleDegrees = angleRadians * 180 / Math.PI;
            return angleDegrees;
        }
    }
}